package com.small.nine.wxmp.utils.wx;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import lombok.extern.slf4j.Slf4j;

import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Json 相关工具类
 *
 * @author sheng_zs@126.com
 * @date 2021-08-05 15:57
 */
@Slf4j
public class JsonUtils {
    private static final ObjectMapper MAPPER;

    static {
        ObjectMapper mapper = new ObjectMapper();
        // 忽略无法识别的字段
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 在序列化时，忽略值为 null 的属性
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // 忽略值为默认值的属性
//        mapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_DEFAULT);
        // 时间格式
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        MAPPER = mapper;
    }

    /**
     * 将 json 字符串转化为 Java Bean
     *
     * @param target json 字符串
     * @param cls    Java Bean 的字节码对象
     * @param <T>    泛型
     * @return Java Bean
     */
    public static <T> T readValue(String target, Class<T> cls) {
        try {
            return MAPPER.readValue(target, cls);
        } catch (Exception e) {
            log.error("json [{}] to bean [{}] 错误", target, cls);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * <p>将 json 字符串转化为 T 对象</p><br>
     * 栗子：
     * <ol>
     *     <li>Set<String> set = readValue("[\"1\"]", new TypeReference<Set<String>>() {});</li>
     *     <li>List<String> list = readValue("[\"1\"]", new TypeReference<List<String>>() {});</li>
     *     <li>Map<String, Object> map = readValue("{\"1\": \"a\"}", new TypeReference<Map<String, Object>>() {});</li>
     * </ol>
     *
     * @param target json
     * @param type   {@link TypeReference} new TypeReference<T>{}
     * @param <T>    泛型，转化的对象类型
     * @return T
     */
    public static <T> T readValue(String target, TypeReference<T> type) {
        try {
            return MAPPER.readValue(target, type);
        } catch (Exception e) {
            log.error("json [{}] to List [e:{}] 错误", target, type);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * <p>将 json 字符串转化为 Map<K, V> 对象</p>
     *
     * @param target json 字符串
     * @param kCls   key 类型
     * @param vCls   value 类型
     * @param <K>    key 泛型
     * @param <V>    value 泛型
     * @return Map<K, V>
     */
    public static <K, V> Map<K, V> readValueAsMap(String target, Class<K> kCls, Class<V> vCls) {
        try {
            JsonNode jsonNode = MAPPER.readTree(target);
            return MAPPER.readValue(target, TypeFactory.defaultInstance().constructMapType(Map.class, kCls, vCls));
        } catch (Exception e) {
            log.error("json [{}] to Map [k:{}, v:{}] 错误", target, kCls, vCls);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * <p>将 json 字符串转化为 Map<String, Object> 对象</p>
     *
     * @param target json 字符串
     * @return Map<String, Object>
     */
    public static Map<String, Object> readValueAsMap(String target) {
        return readValue(target, new TypeReference<Map<String, Object>>() {
        });
    }

    /**
     * <p>将 json 字符串转化为 List<E> 对象</p>
     *
     * @param target json 字符串
     * @param eCls   成员字节码对象
     * @param <E>    成员 泛型
     * @return List<E>
     */
    public static <E> List<E> readValueAsList(String target, Class<E> eCls) {
        try {
            return MAPPER.readValue(target, TypeFactory.defaultInstance().constructCollectionType(List.class, eCls));
        } catch (Exception e) {
            log.error("json [{}] to List [e:{}] 错误", target, eCls);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * <p>将 json 字符串转化为 Set<E> 对象</p>
     *
     * @param target json 字符串
     * @param eCls   成员字节码对象
     * @param <E>    成员 泛型
     * @return Set<E>
     */
    public static <E> Set<E> readValueAsSet(String target, Class<E> eCls) {
        try {
            return MAPPER.readValue(target, TypeFactory.defaultInstance().constructCollectionType(Set.class, eCls));
        } catch (Exception e) {
            log.error("json [{}] to Set [e:{}] 错误", target, eCls);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 将 json 字符串转化为 JsonNode 对象
     *
     * @param target json 字符串
     * @return {@link JsonNode}
     */
    public static JsonNode readTree(String target) {
        try {
            return MAPPER.readTree(target);
        } catch (Exception e) {
            log.error("json [{}] to JsonNode 错误", target);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 将 Java Bean o 转化为 字符串
     *
     * @param o Java Bean
     * @return Json 字符串
     */
    public static String writeValueAsString(Object o) {
        try {
            return MAPPER.writeValueAsString(o);
        } catch (Exception e) {
            log.error("bean [{}] to json 错误", o);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 将 Java Bean o 转化为 byte[]
     *
     * @param o Java Bean
     * @return 字节数组
     */
    public static byte[] writeValueAsBytes(Object o) {
        try {
            return MAPPER.writeValueAsBytes(o);
        } catch (Exception e) {
            log.error("bean [{}] to byte[] 错误", o);
            throw new RuntimeException(e.getMessage());
        }
    }
}
